package common.util;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import common.model.converter.CommonSysAuthorityConverter;
import common.model.enums.SysAuthorityTypeEnum;
import common.model.po.SysAuthority;
import common.model.vo.MenuVo;

import java.util.*;
import java.util.stream.Collectors;

/**
 * vue-router工具类
 *
 * @author 米泽鹏
 * @since 2023-10-31 下午 5:08
 */
public class RouteUtil {

	public static Set<MenuVo> buildRoutes(List<SysAuthority> authorityList) {
		Map<Long, SysAuthority> mapById = Maps.newHashMap();
		authorityList.forEach(authority -> mapById.put(authority.getId(), authority));
		Map<Long, List<SysAuthority>> mapByParentId = authorityList.stream().collect(Collectors.groupingBy(SysAuthority::getParentId));
		// 根节点
		Set<MenuVo> root = Sets.newLinkedHashSet();
		int currentSortForPromoted = 1;
		a:
		for (SysAuthority authority : authorityList) {
			if (!SysAuthorityTypeEnum.STRUCTURE.getValue().equals(authority.getType())) {
				if (authority.getParentId().equals(0L)) {
					MenuVo menuVO = CommonSysAuthorityConverter.poToMenuVo(authority);
					menuVO.getMeta().setFullPath(menuVO.getPath());
					root.add(menuVO);
				} else {
					// 如果自身不是仅结构类型且所有上级都是仅结构类型的，那么也应当被当作根节点
					SysAuthority currentNode = authority;
					while (currentNode.getParentId() != 0 && !SysAuthorityTypeEnum.STRUCTURE.getValue().equals(authority.getType())) {
						SysAuthority parent = mapById.get(currentNode.getParentId());
						if (!SysAuthorityTypeEnum.STRUCTURE.getValue().equals(parent.getType())) {
							continue a;
						}
						currentNode = parent;
					}
					MenuVo menuVO = CommonSysAuthorityConverter.poToMenuVo(authority);
					menuVO.getMeta().setFullPath(menuVO.getPath());
					menuVO.getMeta().setIsPromoted(true);
					menuVO.getMeta().setSort(currentSortForPromoted++);
					root.add(menuVO);
				}
			}
		}
		root.forEach(menuVo -> findChildren(menuVo, mapByParentId));
		// 获取当前最大的sort（除晋升上来的）
		final Integer[] maxSort = {0};
		root.stream().filter(item -> !item.getMeta().getIsPromoted()).forEach(item -> {
			if (item.getMeta().getSort() > maxSort[0]) {
				maxSort[0] = item.getMeta().getSort();
			}
		});
		// 为晋升上来的重新安排sort
		root.stream().filter(item -> item.getMeta().getIsPromoted()).sorted(Comparator.comparingInt(item -> item.getMeta().getSort())).forEach(item -> {
			maxSort[0] = maxSort[0] + 1;
			item.getMeta().setSort(maxSort[0]);
		});
		root = root.stream().sorted(Comparator.comparingInt(item -> item.getMeta().getSort())).collect(Collectors.toCollection(LinkedHashSet::new));
		root.forEach(RouteUtil::flattenChildren);
		return root;
	}

	/**
	 * 去掉类型为“仅结构”的菜单，并使下级晋升
	 */
	private static void flattenChildren(MenuVo menuVO) {
		List<MenuVo> children = menuVO.getChildren();
		List<MenuVo> childrenToBePromoted = Lists.newArrayList();
		Iterator<MenuVo> iterator = children.iterator();
		while (iterator.hasNext()) {
			MenuVo child = iterator.next();
			if (SysAuthorityTypeEnum.STRUCTURE.getValue().equals(child.getMeta().getType())) {
				iterator.remove();
				childrenToBePromoted.addAll(child.getChildren());
			}
		}
		// 获取当前最大的sort
		final Integer[] maxSort = {0};
		children.forEach(item -> {
			if (item.getMeta().getSort() > maxSort[0]) {
				maxSort[0] = item.getMeta().getSort();
			}
		});
		// 晋升的下级排在最后面
		for (int i = 0; i < childrenToBePromoted.size(); i++) {
			childrenToBePromoted.get(i).getMeta().setSort(maxSort[0] + i + 1);
		}
		children.addAll(childrenToBePromoted);
		while (children.stream().anyMatch(item -> SysAuthorityTypeEnum.STRUCTURE.getValue().equals(item.getMeta().getType()))) {
			flattenChildren(menuVO);
		}
		menuVO.getChildren().sort(Comparator.comparingInt(item -> item.getMeta().getSort()));
		children.forEach(RouteUtil::flattenChildren);
	}

	/**
	 * 递归查找子节点
	 */
	private static void findChildren(MenuVo menuVO, Map<Long, List<SysAuthority>> mapByParentId) {
		List<SysAuthority> children = mapByParentId.get(menuVO.getMeta().getId());
		if (children == null) {
			return;
		}
		for (SysAuthority child : children) {
			MenuVo childMenuVo = CommonSysAuthorityConverter.poToMenuVo(child);
			childMenuVo.getMeta().setFullPath(menuVO.getMeta().getFullPath() + childMenuVo.getPath());
			findChildren(childMenuVo, mapByParentId);
			menuVO.getChildren().add(childMenuVo);
		}
		menuVO.getChildren().sort(Comparator.comparingInt(item -> item.getMeta().getSort()));
	}

}
